import { computed, onMounted, reactive, ref } from "vue";
import {
  type ClusterInfo,
  type ConfigMap,
  type Container,
  type CronJob,
  type DaemonSetSpec,
  type Deployment,
  type DeploymentSpec,
  type JobSpec,
  type Namespace,
  type NodeInfo,
  type PersistentVolumeClaim,
  type PodSpec,
  type Secret,
  type Service,
  type StatefulSet,
  type StatefulSetSpec,
  type StorageClass,
  type Volume,
  useK8SApi
} from "../../../api/k8s";
import {
  type VolumeSimpleType,
  type VolumeSimpleInfo,
  WorkloadEditContainerType,
  WorkloadType
} from "@/views/domain/kubeHud/views/components/ko-workloads/types";
import { useFormRule } from "../../../utils/rules";
import { useVerifyRouter } from "@/router/use";
import { ElMessageBox } from "element-plus";

export * from "@/views/domain/kubeHud/views/components/ko-workloads/types";

const {
  deploymentRepo,
  statefulSetRepo,
  daemonSetRepo,

  serviceRepo,
  namespaceRepo,
  configMapRepo,
  nodeRepo,
  clusterRepo,
  storageClassRepo,
  pvcRepo,
  secretRepo
} = useK8SApi();

function _ListRef<T = any>(def?: T[]) {
  return ref<T[]>(def ?? []);
}

export const useWorkloadResource = () => {
  const namespaceList = _ListRef<Namespace>();
  const nodeList = _ListRef<NodeInfo>();
  const secretList = _ListRef<Secret>();
  const configMapList = _ListRef<ConfigMap>();
  const serviceList = _ListRef<Service>();
  const pvcList = _ListRef<PersistentVolumeClaim>();
  const volumeList = _ListRef<VolumeSimpleInfo>();
  const clusterList = _ListRef<ClusterInfo>();
  const storageClassList = _ListRef<StorageClass>();

  const getWorkloadDetails = async (args: {
    cluster: string;
    type: WorkloadType;
    name: string;
    namespace: string;
  }): Promise<any> => {
    try {
      switch (args.type) {
        case WorkloadType.Deployment:
          return await deploymentRepo.getDeploymentDetail({
            namespace: args.namespace,
            srcName: args.name
          });
        case WorkloadType.StatefulSet:
          return await statefulSetRepo.getStatefulSetDetail({
            namespace: args.namespace,
            srcName: args.name
          });
        case WorkloadType.DaemonSet:
          return await daemonSetRepo.getDaemonSetDetail({
            namespace: args.namespace,
            srcName: args.name
          });
      }
    } catch (err) {
      console.error(err);
      return null;
    }
  };

  return {
    source: {
      namespaceList,
      nodeList,
      secretList,
      configMapList,
      serviceList,
      pvcList,
      volumeList,
      clusterList,
      storageClassList
    },
    getWorkloadDetails
  };
};

/**
 *  编辑工作负载
 *
 */
export const useWorkloadEditing = () => {
  const router = useVerifyRouter();

  const editState = reactive({
    // 编辑的资源类型
    workloadType: WorkloadType.None,
    // 集群名称
    cluster: "",
    // 命名空间
    namespace: "",
    // 资源名称
    name: "",

    operation: "", // 当前操作类型
    loading: false,
    readonly: false,
    showYaml: false,
    spanWidth: 12,

    // container
    currentContainerIndex: 0,
    currentContainerType: WorkloadEditContainerType.Standard
  });

  const editWorkload = ref<Deployment | StatefulSet | CronJob | any>({
    apiVersion: "v1",
    kind: "",
    metadata: {
      name: "",
      namespace: "",
      labels: {},
      annotations: {}
    },
    spec: {
      replicas: 1,
      selector: {},
      strategy: {},
      updateStrategy: {},
      template: {
        spec: {
          volumes: []
        }
      }
    }
  });

  const editSpec = computed<
    DeploymentSpec | StatefulSetSpec | DaemonSetSpec | JobSpec
  >(() => {
    return editWorkload.value.spec;
  });

  const editPodSpec = computed<PodSpec | JobSpec | any>(() => {
    switch (editState.workloadType) {
      case WorkloadType.CronJob:
        if (!editWorkload.value?.spec?.jobTemplate.spec.template.spec) {
          editWorkload.value.spec.jobTemplate.spec.template.spec = {};
        }
        return editWorkload.value?.spec?.jobTemplate.spec.template.spec;
      default:
        if (!editWorkload.value?.spec?.template?.spec) {
          editWorkload.value.spec.template.spec = {
            initContainers: [],
            containers: []
          };
        }
        return editWorkload.value?.spec?.template?.spec;
    }
  });

  const editMetadata = computed(() => {
    switch (editState.workloadType) {
      case WorkloadType.CronJob:
        return editWorkload.value?.spec?.jobTemplate.spec.template.metadata;
      default:
        return editWorkload.value?.spec?.template.metadata;
    }
  });

  const editContainer = computed<Container | undefined | null>(() => {
    if (editState.currentContainerType === WorkloadEditContainerType.Standard) {
      if (
        editPodSpec.value.containers &&
        editPodSpec.value.containers.length > editState.currentContainerIndex
      ) {
        return editPodSpec.value.containers[editState.currentContainerIndex];
      }
    } else {
      if (
        editPodSpec.value.initContainers &&
        editPodSpec.value.initContainers.length >
          editState.currentContainerIndex
      ) {
        return editPodSpec.value.initContainers[
          editState.currentContainerIndex
        ];
      }
    }
  });

  const editService = ref<Service>();

  const isStandardContainerType = computed(
    () => editState.currentContainerType === WorkloadEditContainerType.Standard
  );

  const updateContainerName = (name: string) => {
    if (isStandardContainerType.value) {
      editPodSpec.value.containers[editState.currentContainerIndex].name = name;
    } else {
      editPodSpec.value.initContainers[editState.currentContainerIndex].name =
        name;
    }
  };

  // 加载路由参数
  const loadRouteQuery = () => {
    {
      if (!router.verifyRoute()) {
        ElMessageBox.alert("非法路径,请勿修改地址栏参数").then(() => {
          router.back();
        });
        return;
      }

      const { cluster, namespace, name, type, operation, yaml } = router.query;
      cluster && (editState.cluster = `${cluster}`);
      namespace && (editState.namespace = `${namespace}`);
      type && (editState.workloadType = `${type}` as WorkloadType);
      name && (editState.name = `${name}`);
      operation && (editState.operation = `${operation}`);
      yaml && yaml === "true" && (editState.showYaml = true);

      switch (type) {
        case WorkloadType.Deployment:
          editWorkload.value = deploymentRepo.newEntity();
          break;
        case WorkloadType.StatefulSet:
          editWorkload.value = statefulSetRepo.newEntity();
          break;
        case WorkloadType.DaemonSet:
          editWorkload.value = daemonSetRepo.newEntity();
          break;
      }
    }

    {
      const { name } = router.params;
      name && !editState.name && (editState.name = `${name}`);
    }
    console.log("route args: ", editState);
  };

  const routerBack = () => {
    router.back();
  };

  const { NumberRule, RequiredRule, SelectRule, CommonNameRule } =
    useFormRule();

  const operationIsCreate = computed<boolean>(
    () => editState.operation === "create"
  );

  return {
    editWorkload,
    editSpec,
    editPodSpec,
    editContainer,
    editState,
    editMetadata,
    editService,
    router,
    loadRouteQuery,
    routerBack,
    rules: {
      number: [NumberRule],
      required: [RequiredRule],
      select: [SelectRule],
      name: [CommonNameRule]
    },
    operationIsCreate,
    containerTypeIs: {
      standard: isStandardContainerType
    },
    typeIs: {
      pod: computed(() => editState.workloadType === WorkloadType.Pod),
      cronJob: computed(() => editState.workloadType === WorkloadType.CronJob),
      job: computed(() => editState.workloadType === WorkloadType.Job),
      replicateSet: computed(
        () =>
          editState.workloadType === WorkloadType.Deployment ||
          editState.workloadType === WorkloadType.StatefulSet
      ),
      deployment: computed(
        () => editState.workloadType === WorkloadType.Deployment
      ),
      statefulSet: computed(
        () => editState.workloadType === WorkloadType.StatefulSet
      )
    },
    updateContainerName
  };
};

/**
 *  编辑上下文
 * @returns
 */
export const useWorkloadEditor = () => {
  const {
    editWorkload,
    editState,
    editContainer,
    editMetadata,
    editService,
    editSpec,
    editPodSpec,
    typeIs,
    operationIsCreate,
    containerTypeIs,
    loadRouteQuery,
    rules,
    routerBack,
    updateContainerName
  } = useWorkloadEditing();
  const { source, getWorkloadDetails } = useWorkloadResource();

  // clusterIP为None的service 名称列表
  const headlessServiceNames = _ListRef<string>();

  // 重新加载资源详情
  const loadWorkloadDetails = async () => {
    editState.loading = true;
    const workload = await getWorkloadDetails({
      cluster: editState.cluster,
      type: editState.workloadType,
      name: editState.name,
      namespace: editState.namespace
    });
    if (!workload) {
      editState.loading = false;
      return;
    }

    editWorkload.value = Object.assign({}, workload);
    delete editWorkload.value?.metadata?.resourceVersion;

    editState.currentContainerIndex = 0;

    editState.loading = false;
  };

  const createWorkload = async () => {
    const { workloadType } = editState;

    switch (workloadType) {
      case WorkloadType.Deployment:
        return await deploymentRepo.createDeployment(editWorkload.value);
      case WorkloadType.StatefulSet:
        return await statefulSetRepo.createStatefulSet(editWorkload.value);
      case WorkloadType.DaemonSet:
        return await daemonSetRepo.createDaemonSet(editWorkload.value);
    }
  };

  const reloadServiceList = async () => {
    const { items } = await serviceRepo.getService({
      cluster: editState.cluster,
      namespace: editState.namespace
    });

    source.serviceList.value = items;
    headlessServiceNames.value = items
      .filter(item => item.spec.clusterIP === "None")
      .map(item => item.metadata.name);
  };

  const reloadConfigMapList = async () => {
    const { items } = await configMapRepo.getConfigMap({
      cluster: editState.cluster,
      namespace: editState.namespace
    });

    source.configMapList.value = items;
  };

  const reloadClusterList = async () => {
    const { data } = await clusterRepo.getClusterList();

    source.clusterList.value = data.list;
  };

  const reloadNodes = async () => {
    const { items } = await nodeRepo.getNodeList({
      cluster: editState.cluster
    });

    source.nodeList.value = items;
  };

  const reloadNamespaces = async () => {
    const { items } = await namespaceRepo.getNamespaceList({
      cluster: editState.cluster
    });

    source.namespaceList.value = items;
  };

  const mergeVolumes = (
    type?: VolumeSimpleType & "All",
    volumes?: (Volume | VolumeSimpleInfo)[],
    volumeClaimTpls?: (PersistentVolumeClaim | VolumeSimpleInfo)[]
  ) => {
    if (type === "All") {
      source.volumeList.value = volumes?.map(v => ({
        name: v.name,
        type: parseVolumeType(v),
        belongTo: "Volume"
      }));

      source.volumeList.value.push(
        ...(volumeClaimTpls?.map((v: PersistentVolumeClaim) => ({
          name: v.metadata.name,
          type: "VolumeClaimTemplates" as VolumeSimpleType,
          belongTo: "VolumeClaimTemplates" as VolumeSimpleType
        })) ?? [])
      );
    } else {
      source.volumeList.value = source.volumeList.value.filter(
        v => v.belongTo !== type
      );

      source.volumeList.value.push(
        ...(volumes?.map((v: VolumeSimpleInfo) =>
          Object.assign(v, { belongTo: "Volume" })
        ) ?? [])
      );

      source.volumeList.value.push(
        ...(volumeClaimTpls?.map((v: VolumeSimpleInfo) =>
          Object.assign(v, { belongTo: "Volume", type: "VolumeClaimTemplates" })
        ) ?? [])
      );
    }
  };

  const reloadStorageClassList = async () => {
    const { items } = await storageClassRepo.listStorageClasses({});

    source.storageClassList.value = items;
  };

  const parseVolumeType = (v: Volume): VolumeSimpleType | undefined => {
    if (v.configMap) {
      return "ConfigMap";
    } else if (v.secret) {
      return "Secret";
    } else if (v.persistentVolumeClaim) {
      return "PVC";
    } else if (v.emptyDir) {
      return "EmptyDir";
    } else if (v.hostPath) {
      return "HostPath";
    } else if (v.nfs) {
      return "NFS";
    }
  };

  const reloadPvcList = async () => {
    const { items } = await pvcRepo.getPVC({
      cluster: editState.cluster,
      namespace: editState.namespace
    });

    source.pvcList.value = items;
  };

  const reloadSecretList = async () => {
    const { items } = await secretRepo.getSecret({
      cluster: editState.cluster,
      namespace: editState.namespace
    });

    source.secretList.value = items;
  };

  onMounted(() => {
    loadRouteQuery();
    reloadNodes();
    reloadSecretList();
  });
  return {
    editState,
    editWorkload,
    editContainer,
    editSpec,
    editPodSpec,
    editMetadata,
    editRules: rules,
    editService,
    routerBack,

    source,
    headlessServiceNames,

    typeIs,
    containerTypeIs,
    operationIsCreate,
    serviceEditable: computed(
      () =>
        !typeIs.cronJob.value && !typeIs.job.value && operationIsCreate.value
    ),
    updateContainerName,

    loadWorkloadDetails,
    reloadClusterList,
    reloadConfigMapList,
    reloadNamespaces,
    reloadNodes,
    reloadServiceList,
    reloadStorageClassList,
    mergeVolumes,
    reloadPvcList,
    reloadSecretList,
    createWorkload
  };
};
